package com.sky.controller.admin;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.result.Result;
import com.sky.service.CategoryService;
import com.sky.service.DishFlavorService;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 菜品管理
 */
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {
    @Autowired
    private DishService dishService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private DishFlavorService dishFlavorService;
    @Autowired
    RedisTemplate  redisTemplate;

    /**
     * 根据查询条件分页获取菜品信息
     * 此方法通过接收一个 DishPageQueryDTO 对象作为参数，该对象包含分页查询所需的条件和参数，
     * 如页码、每页记录数、分类ID、菜品名称和状态等，以实现对菜品信息的条件过滤和分页查询
     *
     * @param dto 包含分页查询条件和参数的对象
     * @return 返回一个 Result 对象，其中包含查询结果
     */
    @GetMapping("/page")
    @ApiOperation("菜品分页查询")
    public Result page(DishPageQueryDTO dto){
        // 初始化Page对象，用于分页查询
        Page<Dish> page = new Page<>(dto.getPage(), dto.getPageSize());

        // 根据DTO中的查询条件构建查询链，执行分页查询
        dishService.query()
                .eq(dto.getCategoryId()!=null,"category_id",dto.getCategoryId())
                .like(dto.getName()!=null,"name",dto.getName())
                .eq(dto.getStatus()!=null,"status",dto.getStatus())
                .orderByDesc("update_time")
                .page(page);

        //将page转换为DishVo对象
        // 此处对查询结果进行处理，将每条记录转换为DishVO对象，并设置分类名称
        Page<DishVO> convert =(Page<DishVO>)page.convert(dish -> {
            DishVO dishVO = BeanUtil.toBean(dish, DishVO.class);
            // 根据分类ID获取分类名称，并设置到DishVO对象中
            dishVO.setCategoryName(categoryService.getById(dish.getCategoryId()).getName());
            return dishVO;
        });

        // 返回查询结果
        return Result.success(convert);
    }

    /**
     * 添加菜品接口
     *
     * 该方法接收一个DishDTO对象作为参数，用于创建并保存一个新的菜品及其相关口味信息
     *
     * @param dto 菜品数据传输对象，包含菜品的基本信息和口味信息
     * @return 返回一个Result对象，表示菜品添加操作的结果
     */
    @PostMapping
    @ApiOperation("添加菜品")
    public Result addDish(@RequestBody DishDTO dto){
        //将DTO转换为Dish对象，便于后续操作和保存到数据库
        Dish dish = BeanUtil.toBean(dto, Dish.class);

        //设置菜品的创建时间和更新时间为当前时间
        dish.setCreateTime(LocalDateTime.now());
        dish.setUpdateTime(LocalDateTime.now());
        //设置菜品状态为1，通常表示菜品是可用的或激活的状态
        dish.setStatus(1);
        //保存菜品信息到数据库
        dishService.save(dish);

        //遍历DTO中的口味列表，为每个口味创建记录并关联到刚刚添加的菜品
        List<DishFlavor> flavors = dto.getFlavors();
        flavors.forEach(flavor->{
            //设置当前口味所关联的菜品ID
            flavor.setDishId(dish.getId());

            //插入口味信息到数据库
            dishFlavorService.save(flavor);
        });

        //删除缓存
        delDish("dish_"+dto.getCategoryId());

        //返回成功结果，表示菜品及其口味信息已成功添加
        return Result.success();
    }

    /**
     * 批量删除菜品接口
     * 该接口允许用户根据菜品ID列表批量删除菜品及其相关口味信息
     *
     * @param ids 要删除的菜品ID列表
     * @return 返回一个表示操作结果的成功结果对象
     */
    @DeleteMapping
    @ApiOperation("批量删除菜品")
    public Result<Void> deleteDish(@RequestParam List<Long> ids){
        //1. 删除菜品信息
        //   根据提供的菜品ID列表，批量删除菜品信息
        dishService.removeBatchByIds(ids);

        //2. 删除口味信息
        //   删除与被删除菜品相关联的所有口味信息
        dishFlavorService.update().in("dish_id", ids).remove();

        //删除缓存
        delDish("dish_*");

        //3. 返回成功结果
        //   所有相关数据删除成功后，返回一个表示操作成功的Result对象
        return Result.success();
    }

    /**
     * 根据ID获取菜品详细信息
     * 此方法首先从dishService中获取菜品基本信息，然后从dishFlavorService中查询与该菜品ID关联的所有口味信息
     * 最后，将菜品信息和其对应的口味信息封装成一个DishVO对象，并返回给调用者
     *
     * @param id 菜品的唯一标识符，用于查询特定菜品及其口味信息
     * @return 包含菜品及其口味信息的DishVO对象，如果查询成功，则返回成功结果
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询菜品")
    public Result getById(@PathVariable Long id){
        // 根据菜品ID获取菜品基本信息
        Dish dish = dishService.getById(id);

        // 查询与该菜品ID关联的所有口味信息
        List<DishFlavor> flavors = dishFlavorService.query().eq("dish_id", id).list();

        // 将菜品信息转换为DishVO对象
        DishVO dishVO = BeanUtil.toBean(dish, DishVO.class);

        // 将口味信息设置到DishVO对象中
        dishVO.setFlavors(flavors);

        // 返回包含菜品及其口味信息的成功结果
        return Result.success(dishVO);
    }

    /**
     * 更新菜品信息
     * 此方法首先将传入的DishDTO对象转换为Dish对象，并更新数据库中的菜品基本信息
     * 然后删除数据库中与该菜品相关的所有口味信息，最后重新保存传入的口味信息
     *
     * @param dto 菜品数据传输对象，包含要更新的菜品信息和其对应的口味信息
     * @return 返回更新操作的结果，包括成功或失败的信息
     */
    @PutMapping
    @ApiOperation("修改菜品")
    public Result update(@RequestBody DishDTO dto){
        // 将DishDTO转换为Dish对象，以便更新菜品基本信息
        Dish dish = BeanUtil.toBean(dto, Dish.class);
        dishService.updateById(dish);

        // 删除数据库中与当前菜品相关的所有口味信息，为后续重新保存做准备
        dishFlavorService.update()
                .eq("dish_id",dto.getId())
                .remove();

        // 遍历传入的菜品口味信息，为每个口味设置菜品ID，并保存到数据库中
        dto.getFlavors().forEach(flavor->{
            flavor.setDishId(dto.getId());
            dishFlavorService.save(flavor);
        });

        // 删除菜品缓存
        delDish("dish_*");

        // 返回操作成功的结果
        return Result.success();
    }

    /**
     * 启用或禁用指定菜品
     *
     * @param status 菜品的新状态，0表示禁用，1表示启用
     * @param id 菜品的唯一标识符
     * @return 返回操作结果，成功启用或禁用菜品
     */
    @PostMapping("/status/{status}")
    @ApiOperation("启用或禁用菜品")
    public Result startOrStop(@PathVariable Integer status, Long id) {
        // 更新数据库中的菜品状态
        dishService.update()
                .eq("id", id)
                .set("status", status)
                .update();

        // 删除菜品缓存
        delDish("dish_*");

        // 返回操作成功结果
        return Result.success();
    }

    /**
     * 根据分类ID查询菜品列表
     * 此方法通过分类ID来查询符合条件的菜品列表，并将每个菜品及其对应的口味信息封装到DishVO对象中返回
     *
     * @param categoryId 分类ID，用于查询特定分类下的菜品列表
     * @return 返回一个Result对象，其中包含一个DishVO对象的列表，每个DishVO对象代表一个菜品及其口味信息
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品列表")
    public Result<List<DishVO>> listByCategory(Long categoryId) {
        // 查询符合条件的菜品列表
        List<Dish> list = dishService.query()
                .eq(categoryId != null, "category_id", categoryId)
                .eq("status", 1)
                .list();

        // 将查询到的菜品列表转换为DishVO列表，并为每个DishVO补全口味数据
        List<DishVO> dishVOS = list.stream().map(dish -> {
            // 将Dish对象转换为DishVO对象
            DishVO dishVO = BeanUtil.toBean(dish, DishVO.class);
            // 补全口味数据
            List<DishFlavor> flavors = dishFlavorService.query().eq("dish_id", dish.getId()).list();
            dishVO.setFlavors(flavors);
            return dishVO;
        }).collect(Collectors.toList());

        // 返回成功结果，包含菜品列表
        return Result.success(dishVOS);
    }

    /**
     * 根据指定的模式删除Redis中的键值对
     * 此方法用于批量删除符合特定模式的键，以实现批量清理缓存的目的
     *
     * @param pattern 模式字符串，用于匹配待删除的键例如，传入"dish:*"将删除所有以"dish:"开头的键
     */
    private void delDish(String pattern) {
        // 获取所有符合指定模式的键
        Set keys = redisTemplate.keys(pattern);
        // 删除获取到的所有键
        redisTemplate.delete(keys);
    }


}
